const { getLiveServerUrl } = require("./../configuration");

// Ensure ThreeJS is in global scope for the 'examples/'
global.THREE = require("three");

// Include any additional ThreeJS examples below
require("three/examples/js/controls/OrbitControls");
require("three/examples/js/shaders/CopyShader");
require("three/examples/js/postprocessing/EffectComposer");
require("three/examples/js/postprocessing/RenderPass");
require("three/examples/js/postprocessing/ShaderPass");
require("three/examples/js/postprocessing/TexturePass");
require("three/examples/js/shaders/FXAAShader");

const canvasSketch = require("canvas-sketch");
const glslify = require('glslify');

const settings = {
  animate: true, // Make the loop animated
  context: "webgl", // Get a WebGL canvas rather than 2D
};

const sketch = ({ context }) => {
  const renderer = new THREE.WebGL1Renderer({ canvas: context.canvas }); // Create a renderer
  renderer.autoClear = false;

  renderer.setClearColor("#fff", 1); // WebGL background color

  const camera = new THREE.PerspectiveCamera(50, 1, 0.01, 100); // Setup a camera
  camera.position.set(0, 0, -4);
  camera.lookAt(new THREE.Vector3());

  const controls = new THREE.OrbitControls(camera, context.canvas); // Setup camera controller
  const textureLoader = new THREE.TextureLoader();

  const scene = new THREE.Scene();

  const composer = new THREE.EffectComposer(renderer);
  const pass1 = new THREE.RenderPass(scene, camera);
  composer.addPass(pass1);

  const copyPass = new THREE.ShaderPass(THREE.CopyShader);
  composer.addPass(copyPass);

  const fxaaPass = new THREE.ShaderPass(THREE.FXAAShader);

  const container = document.querySelector('canvas');
  const pixelRatio = renderer.getPixelRatio();

  fxaaPass.material.uniforms['resolution'].value.x = 1 / (container.offsetWidth * pixelRatio);
  fxaaPass.material.uniforms['resolution'].value.y = 1 / (container.offsetHeight * pixelRatio);
  composer.addPass(fxaaPass);

  THREE.ShaderChunk['fireball'] =/* glsl */``;

  const firballGeometry = new THREE.IcosahedronGeometry(1, 20);

  const myMaterial = new THREE.ShaderMaterial({
    transparent: true,
    side: THREE.FrontSide,
    uniforms: {
      // 50b7d1901c4a11ecb4000a80ff2603de d1fd3b181cdc11eca5a80a80ff2603de
      "texture": { value: textureLoader.load(getLiveServerUrl("/assets/resources/d1fd3b181cdc11eca5a80a80ff2603de.png")) },
      "time": { value: 0.0 }
    },
    vertexShader: glslify(/* glsl */`
            #pragma glslify: cnoise4 = require('glsl-noise/classic/4d');
            #pragma glslify: pnoise4 = require('glsl-noise/periodic/4d');

            varying vec2 vUv;
            varying vec3 vPosition;
            varying float offset;

            uniform float explosure;
            uniform float time;

            void main() {
                vUv = uv;

                // 改变多面体的顶点
                float n1 = cnoise4(vec4(position, 1.0) + 0.7 * vec4(time)) + 1.0;

                float d = pow(n1, 2.0);

                // 改变多面体细节
                float n2 =  pnoise4(6.5 * vec4(position, 1.0) + vec4(time) - vec4(d), vec4(100.0));

                vPosition = position * (1.0 + 0.9 * n1 + 0.15 * n2); // 影响几何

                offset =  (0.5 * n1 + 0.05) + (0.1 * n2); // 影响片元

                gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1.0);
            }
        `),
    fragmentShader:/* glsl */`
            varying vec2 vUv;
            varying vec3 vPosition;
            varying float offset;

            uniform float time;
            uniform float explosure;
            uniform sampler2D texture;

            float random(vec3 scale, float seed){
                return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed) ;
            }

            void main() {
                float r = .01 * random( vec3( 12.9898, 78.233, 151.7182 ), 0.0 ); // 让颜色看起来不这么死板, 添加一个random函数
                vec4 color = texture2D(texture, vec2(0.0, min(offset, 1.0) - r));
                gl_FragColor = vec4(color.rgb, 1.0);
                // gl_FragColor = vec4(vec3(1.0 - offset), 1.0);
            }
        `
  })

  const fireball = new THREE.Mesh(firballGeometry, myMaterial);
  scene.add(fireball);

  // draw each frame
  return {
    // Handle resize events here
    resize({ pixelRatio, viewportWidth, viewportHeight }) {
      renderer.setPixelRatio(pixelRatio);
      renderer.setSize(viewportWidth, viewportHeight, false);
      camera.aspect = viewportWidth / viewportHeight;
      camera.updateProjectionMatrix();
    },
    // Update & render your scene here
    render({ time }) {
      myMaterial.uniforms.time.value = time;

      controls.update();
      composer.render();
    },
    // Dispose of events & renderer for cleaner hot-reloading
    unload() {
      controls.dispose();
      renderer.dispose();
    }
  };
};

canvasSketch(sketch, settings);
